package com.jd.dlc.limit.dynamic;

import com.jd.dlc.domain.DLCLimitRule;
import com.jd.dlc.domain.LimiterRule;
import com.jd.dlc.domain.WrapLimiterRule;
import com.jd.dlc.limit.scan.Sanner;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * @program: dlc
 * @ClassName LimiterRuleDynamic
 * @description: Dynamic update of current limiting rules
 * @author: sizegang
 * @create: 2022-05-11
 **/
@Slf4j
public class LimiterRuleDynamic extends BLimiterRuleDynamic {


    @Override
    public WrapLimiterRule doLoad(String namespace, String limitKey) {
        WrapLimiterRule.WrapLimiterRuleBuilder ruleBuilder = WrapLimiterRule.builder();

        LimiterRule limiterRule = DlcLimiterRuleFactory.getConfig(namespace);

        if (limiterRule == null) {
            return ruleBuilder.build();
        }
        /**
         * Whether the method enables current limiting
         */
        if (!limiterRule.isEnable()) {
            return ruleBuilder.enable(limiterRule.isEnable()).build();
        }
        List<LimiterRule.LRule> rules = limiterRule.getRules();
        if (Objects.nonNull(rules) && StringUtils.isNotBlank(limitKey)) {
            for (LimiterRule.LRule rule : rules) {
                Set<String> keys = rule.getKeys();
                if (keys.contains(limitKey)) {
                    ruleBuilder.timeout(rule.getTimeout());
                    ruleBuilder.limit(rule.getLimit());
                    ruleBuilder.enable(rule.isEnable());
                    ruleBuilder.truncateEnd(rule.getTruncateEnd());
                    ruleBuilder.truncateEnd(rule.getTruncateEnd());
                    ruleBuilder.recordLimit(rule.isRecordLimit());
                    /**
                     * in milliseconds
                     */
                    ruleBuilder.recordTime(rule.getRecordTime());
                    /**
                     * Grayscale ratio control
                     */
                    ruleBuilder.gray(rule.getGray());
                    ruleBuilder.advanced(rule.isAdvanced());
                    ruleBuilder.limitNum(rule.getLimitNum());
                    return ruleBuilder.build();
                }
            }
        }
        ruleBuilder.enable(limiterRule.isEnable());
        ruleBuilder.timeout(limiterRule.getTimeout());
        ruleBuilder.limit(limiterRule.getLimit());
        ruleBuilder.truncateStart(limiterRule.getTruncateStart());
        ruleBuilder.truncateEnd(limiterRule.getTruncateEnd());
        ruleBuilder.recordLimit(limiterRule.isRecordLimit());
        ruleBuilder.recordTime(limiterRule.getRecordTime());
        ruleBuilder.gray(limiterRule.getGray());
        ruleBuilder.blackList(limiterRule.getBlackList());
        ruleBuilder.whiteList(limiterRule.getWhiteList());
        ruleBuilder.triggerLimit(limiterRule.isTriggerLimit());
        ruleBuilder.advanced(limiterRule.isAdvanced());
        ruleBuilder.limitNum(limiterRule.getLimitNum());
        return ruleBuilder.build();
    }

    @Override
    boolean doRefresh(DLCLimitRule rules) {
        try {
            DlcLimiterRuleFactory.limitEnable = rules.isEnable();
            rules.getRuleList().stream().forEach(x -> {
                /**
                 * Update configuration and Update limiter
                 */
                DlcLimiterRuleFactory.createUpdate(x.getNamespace(), x);
                Sanner.limits.get(x.getNamespace()).refreshLimiter(x);
            });
            log.info("Limiter Rule update success!!!");
        } catch (Exception ex) {
            log.error("Limiter Rule update error {}", ex);
            return false;
        }
        return true;
    }


}
